package jvn;

import java.io.Serializable;

public class JvnObjectImpl implements JvnObject {



	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;	

	int id;
	Serializable object;
	JvnObjectState state;
	int nbReader = 0;

	public JvnObjectImpl(Serializable object) {
		id = 0;
		this.object = object;
		state = JvnObjectState.STATE_W;
	}

	public int jvnGetObjectId() throws JvnException {
		return id;
	}

	public void jvnSetObjectId(int id) throws JvnException {
		this.id = id;
	}


	public Serializable jvnGetObjectState() throws JvnException {
		return object;
	}

	public void jvnInvalidateReader() throws JvnException {
		synchronized(this) {
			if( state == JvnObjectState.STATE_R ) {
				try {
					while( state == JvnObjectState.STATE_R ) {					
						this.wait();
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				state = JvnObjectState.STATE_NL;
				System.out.println("Object.invalidateR : R -> NL");
			} else if( state == JvnObjectState.STATE_RC ) {
				state = JvnObjectState.STATE_NL;
				System.out.println("Object.invalidateR : RC -> NL");
			}		 
		}
	}

	public Serializable jvnInvalidateWriter() throws JvnException {
		synchronized(this) {
			if( state == JvnObjectState.STATE_W ) {
				try {
					while( state == JvnObjectState.STATE_W ) {					
						this.wait();
					}

				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				state = JvnObjectState.STATE_NL;
				System.out.println("Object.invalidateW : W -> NL");
			} else if( state == JvnObjectState.STATE_WC ) {
				state = JvnObjectState.STATE_NL;
				System.out.println("Object.invalidateW : WC -> NL");
			}		 
			return object;
		}

	}

	public synchronized Serializable jvnInvalidateWriterForReader() throws JvnException {
		if( state == JvnObjectState.STATE_W ) {
			try {
				while( state == JvnObjectState.STATE_W ) {					
					this.wait();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			state = JvnObjectState.STATE_RC;
			System.out.println("Object.invalidateWR : W -> RC");
		} else if( state == JvnObjectState.STATE_WC ) {
			state = JvnObjectState.STATE_RC;
			System.out.println("Object.invalidateWR : WC -> RC");
		}		 
		return object;
	}

	public void jvnLockRead() throws JvnException {
		boolean ask = false;
		synchronized(this) {
			if (state == JvnObjectState.STATE_RC) {
				state = JvnObjectState.STATE_R;
				System.out.println("Object.lockRead : RC -> R");
				nbReader = 1;
			}
			else if (state == JvnObjectState.STATE_R) {
				nbReader++;
				System.out.println("Object.lockRead : R -> R (++)");
			} else {
				ask = true;
			}	
		}
		if (ask) {
			Serializable temp = JvnServerImpl.jvnGetServer().jvnLockRead(id);
			object = temp;
			state = JvnObjectState.STATE_R;
			System.out.println("Object.lockRead : W or NL or WC -> R");
			nbReader = 1;
		}
	}

	public void jvnLockWrite() throws JvnException {
		boolean ask = false;
		synchronized(this) {
			if (state == JvnObjectState.STATE_WC) {
				System.out.println("Object.lockWrite : WC -> W ");
				state = JvnObjectState.STATE_W;
			}
			else {
				ask = true;
			}

		}
		if (ask) {
			Serializable temp = JvnServerImpl.jvnGetServer().jvnLockWrite(id);
			object = temp;
			state = JvnObjectState.STATE_W;
			System.out.println("Object.lockWrite : ALL except WC -> W ");
		}
	}

	public void jvnUnLock() throws JvnException {
		synchronized(this) {
			if (state == JvnObjectState.STATE_R){
				nbReader--;
				if (nbReader <= 0) {
					state = JvnObjectState.STATE_RC;
					System.out.println("Object.unlock : R -> RC");
					this.notifyAll();
				}
			}
			else if (state == JvnObjectState.STATE_W) {
				state = JvnObjectState.STATE_WC;
				System.out.println("Object.unlock : W -> WC");
				this.notifyAll();
			}
		}

	}

}
